using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Collections;

namespace Decav.Collections.ObjectModel
{

    /// <summary>
    /// A ReadOnlyCollection suitable for exposure in object models that provides events for when the list is modified.
    /// </summary>
    /// <remarks>
    /// Only when the list is modified through the <see cref="T:WatchableCollection`1"/> wrapper will the events be raised. That is, if
    /// the WatchableCollection is wrapping another IList object, then if items are added directly to the underlying IList, no events will
    /// be raised.
    /// </remarks>
    /// <typeparam name="T">The type of item that the collection contains.</typeparam>
    [Serializable]
    public class WatchableReadOnlyCollection<T> : ReadOnlyCollection<T>
    {

        #region Event Declarations

        /// <summary>
        /// Event that is raised when an item is added to the collection.
        /// </summary>
        [Description( "Event that is raised when an item is added to the collection." )]
        public event ItemAddedEventHandler<T> Added;

        /// <summary>
        /// Event that is raised when an item is removed from the collection.
        /// </summary>
        [Description( "Event that is raised when an item is removed from the collection." )]
        public event ItemRemovedEventHandler<T> Removed;

        /// <summary>
        /// Event that is raised when an existing item in the list is modified.
        /// </summary>
        [Description( "Event that is raised when an existing item in the list is modified." )]
        public event ItemModifiedEventHandler<T> Modified;

        /// <summary>
        /// Event that is raised when the collection is cleared of all items.
        /// </summary>
        [Description( "Event that is raised when the collection is cleared of all items." )]
        public event EventHandler Cleared;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="T:WatchableReadOnlyCollection`1"/> class.
        /// </summary>
        /// <param name="list">The list to wrap.</param>
        /// <exception cref="T:System.ArgumentNullException">list is null.</exception>
        public WatchableReadOnlyCollection( WatchableCollection<T> list )
            : base( list )
        {

            list.Added += new ItemAddedEventHandler<T>( WrappedList_Added );
            list.Removed += new ItemRemovedEventHandler<T>( WrappedList_Removed );
            list.Modified += new ItemModifiedEventHandler<T>( WrappedList_Modified );
            list.Cleared += new EventHandler( WrappedList_Cleared );

        }

        #endregion

        #region Wrapped Event Handlers

        /// <summary>
        /// Handles the Added event of the WrappedList object.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The ItemAddedEventArgs instance containing the event data.</param>
        private void WrappedList_Added( object sender, ItemAddedEventArgs<T> e )
        {
            OnAdded( e );
        }

        /// <summary>
        /// Handles the Removed event of the WrappedList object.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The ItemRemovedEventArgs instance containing the event data.</param>
        private void WrappedList_Removed( object sender, ItemRemovedEventArgs<T> e )
        {
            OnRemoved( e );
        }

        /// <summary>
        /// Handles the Modified event of the WrappedList object.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The ItemModifiedEventArgs instance containing the event data.</param>
        private void WrappedList_Modified( object sender, ItemModifiedEventArgs<T> e )
        {
            OnModified( e );
        }

        /// <summary>
        /// Handles the Cleared event of the WrappedList object.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void WrappedList_Cleared( object sender, EventArgs e )
        {
            OnCleared( e );
        }

        #endregion

        #region Event Invoke Methods

        /// <summary>
        /// Raises the Added event to event subscribers.
        /// </summary>
        /// <remarks>
        /// Note to inheritors: You must call the base method in order to ensure that the event is raised and clean up
        /// work is properly performed.
        /// </remarks>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnAdded( ItemAddedEventArgs<T> e )
        {

            // Invoke the event handlers
            if ( Added != null )
            {
                Added( this, e );
            }   // if

        }

        /// <summary>
        /// Raises the Removed event to event subscribers.
        /// </summary>
        /// <remarks>
        /// Note to inheritors: You must call the base method in order to ensure that the event is raised and clean up
        /// work is properly performed.
        /// </remarks>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnRemoved( ItemRemovedEventArgs<T> e )
        {

            // Invoke the event handlers
            if ( Removed != null )
            {
                Removed( this, e );
            }   // if

        }

        /// <summary>
        /// Raises the Modified event to event subscribers.
        /// </summary>
        /// <remarks>
        /// Note to inheritors: You must call the base method in order to ensure that the event is raised and clean up
        /// work is properly performed.
        /// </remarks>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnModified( ItemModifiedEventArgs<T> e )
        {

            // Invoke the event handlers
            if ( Modified != null )
            {
                Modified( this, e );
            }   // if

        }

        /// <summary>
        /// Raises the Cleared event to event subscribers.
        /// </summary>
        /// <remarks>
        /// Note to inheritors: You must call the base method in order to ensure that the event is raised and clean up
        /// work is properly performed.
        /// </remarks>
        /// <param name="e">Event arguments.</param>
        protected virtual void OnCleared( EventArgs e )
        {

            // Invoke the event handlers
            if ( Cleared != null )
            {
                Cleared( this, e );
            }   // if

        }

        #endregion

    }   // class

}   // namespace
